package cn.dansj.common.utils.spring.request;

import java.io.IOException;
import java.io.OutputStream;

import cn.dansj.common.utils.lang.Nullable;
import org.springframework.http.HttpHeaders;
import org.springframework.http.StreamingHttpOutputMessage;
import org.springframework.http.client.AbstractClientHttpRequest;
import org.springframework.http.client.ClientHttpResponse;
import org.springframework.util.Assert;
import org.springframework.util.FastByteArrayOutputStream;

abstract class AbstractStreamingClientHttpRequest extends AbstractClientHttpRequest implements StreamingHttpOutputMessage {
    @Nullable
    private Body body;

    @Nullable
    private FastByteArrayOutputStream bodyStream;

    @Override
    protected final OutputStream getBodyInternal(HttpHeaders headers) {
        Assert.state(this.body == null, "Invoke either getBody or setBody; not both");
        if (this.bodyStream == null) this.bodyStream = new FastByteArrayOutputStream(1024);
        return this.bodyStream;
    }

    @Override
    public final void setBody(Body body) {
        Assert.notNull(body, "Body must not be null");
        assertNotExecuted();
        Assert.state(this.bodyStream == null, "Invoke either getBody or setBody; not both");
        this.body = body;
    }

    @Override
    protected final ClientHttpResponse executeInternal(HttpHeaders headers) throws IOException {
        if (this.body == null && this.bodyStream != null) {
            this.body = outputStream -> this.bodyStream.writeTo(outputStream);
        }
        return executeInternal(headers, this.body);
    }

    protected abstract ClientHttpResponse executeInternal(HttpHeaders headers, @Nullable Body body) throws IOException;
}
